package org.arch_learn.io.nio.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class NioSelectorServerDemo {
    public static void main(String[] args) throws IOException {
        //1.打开服务端通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //2.绑定对应端口号
        serverSocketChannel.bind(new InetSocketAddress(9999));
        //3.通道默认是阻塞的，需要手动设置非阻塞
        serverSocketChannel.configureBlocking(false);
        //4.创建选择器
        Selector selector = Selector.open();
        //5.将服务端通道注册到选择器上，并指定注册监听的事件为OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务端启动成功！");
        //6.检查选择器是否有事件
        while (true) {
            //2000代表超时事件，eventCount代表事件个数
            int eventCount = selector.select(2000);
            if (eventCount == 0) {
                System.out.println("没有事件发生！");
                continue;
            }
            //7.获取事件集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                //8.判断事件是否是客户端连接事件SelectionKey.isAcceptable()
                if (selectionKey.isAcceptable()) {
                    //9.得到客户端通道，并将通道注册到选择器上，并指定监听事件为OP_READ
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //将通道设置成非阻塞,因为selector需要轮询监听每个通道的事件
                    socketChannel.configureBlocking(false);
                    System.out.println("有客户端连接。。。");
                    //指定监听事件为OP_READ
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }

                //10.判断是否是客户端读就绪事件
                if (selectionKey.isReadable()) {
                    //11.得到客户端通道，读取数据到缓冲区
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int read = socketChannel.read(byteBuffer);
                    if (read > 0) {
                        String requestMessage = new String(byteBuffer.array(), 0, read, StandardCharsets.UTF_8);
                        System.out.println("读取客户端请求报文为：" + requestMessage);
                        //12.给客户端回写响应
                        ByteBuffer responseByteBuffer = ByteBuffer.wrap("response".getBytes(StandardCharsets.UTF_8));
                        socketChannel.write(responseByteBuffer);
                        socketChannel.close();
                    }
                }

                //13.从集合中删除事件，防止二次处理
                iterator.remove();
            }
        }
    }
}
